package com.zhaojun.cloud.common.net;


import com.zhaojun.cloud.common.util.Detect;
import com.zhaojun.cloud.common.util.FileUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;


public class FtpUtil {

    private static transient Logger logger = LoggerFactory.getLogger(FtpUtil.class);

    private static final String DEFAULT_ENCODING = "gbk";
    private static final String SEPARATOR = "/";

    public static boolean deleteFiles(FtpConfig ftpConfig, List<String> fileNames) {
        return deleteFiles(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), ftpConfig.getDefaultRemoteDir(), fileNames, ftpConfig.getEncoding());
    }

    public static boolean deleteFiles(String username, String password, String serverIp, int port, String remotePath, List<String> fileNames) {
        return deleteFiles(username, password, serverIp, port, remotePath, fileNames, DEFAULT_ENCODING);
    }

    /**
     * 把文件从ftp上的A目录移动到Ftp的B目录 (A目录下不要包括文件夹，只移动文件)
     *
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param remoteDirA
     * @param remoteDirB
     * @param encoding
     * @return
     * @author BingWang
     */

    public static boolean moveFileFromAToB(String username, String password, String serverIp, int port, String remoteDirA, String remoteDirB, String encoding) {
        // 将RemoteDirA中文件拷贝到remoteDirB中，但不删除A中文件
        List<String> fileNames = copyFileFromAToB(username, password, serverIp, port, remoteDirA, remoteDirB, encoding);
        if (fileNames != null && !fileNames.isEmpty()) {
            deleteFiles(username, password, serverIp, port, remoteDirA, fileNames, encoding);
        }
        return true;
    }

    /**
     * 把当前执行过的文件从ftp上的A目录移动到Ftp的B目录 (A目录下不要包括文件夹，只移动文件)
     *
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param fileNames
     * @param remoteDirA
     * @param remoteDirB
     * @param encoding
     * @return
     */
    public static boolean moveExecutedFileFromAToB(String username, String password, String serverIp, int port, List<String> fileNames, String remoteDirA, String remoteDirB, String encoding) {
        if (fileNames != null && !fileNames.isEmpty()) {
            // 将RemoteDirA中文件拷贝到remoteDirB中，但不删除A中文件
            copyExecutedFileFromAToB(username, password, serverIp, port, fileNames, remoteDirA, remoteDirB, encoding);
            return deleteFiles(username, password, serverIp, port, remoteDirA, fileNames, encoding);
        }
        return false;
    }

    /**
     * 把文件从ftp上的A目录拷贝到Ftp的B目录 (A目录下不包括文件夹，只拷贝文件)
     *
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param remoteDirA 必须已经存在
     * @param remoteDirB 可以不存在，在该方法中建立
     * @param encoding
     * @return fileNames 返回拷贝到另一个目录的文件名字集合
     * @author BingWang
     */

    public static List<String> copyFileFromAToB(String username, String password, String serverIp, int port, String remoteDirA, String remoteDirB, String encoding) {
        String tmpDir = "./ftpCopyTmp";
        FTPClient ftpClient = null;
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.changeWorkingDirectory(remoteDirA);
            FTPFile[] allftpFiles = ftpClient.listFiles();
            List<String> validFtpFiles = new ArrayList<String>();
            for (FTPFile ftpf : allftpFiles) {
                if (ftpf.isFile()) {
                    getFile(username, password, serverIp, port, remoteDirA, ftpf.getName(), tmpDir, encoding);// 远程文件拉去到本地临时目录
                    validFtpFiles.add(ftpf.getName());
                }
            }
            // 创建remoteDirB，无论存在与否。如果存在，则不会做动作；如果不存在，则创建
            // 如果要创建/home/pboss/abc 这个目录，则将parentDir设置成""就可以了
            makeDir(username, password, serverIp, port, "", remoteDirB, encoding);// 建立目录
            putFile(username, password, serverIp, port, tmpDir, validFtpFiles, remoteDirB, encoding);// 上传文件到远程目录
            FileUtil.cleanDir(new File(tmpDir));// 清空本地临时目录
            return validFtpFiles;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return null;
    }

    public static List<String> copyExecutedFileFromAToB(String username, String password, String serverIp, int port, List<String> fileNames, String remoteDirA, String remoteDirB, String encoding) {
        String tmpDir = "./ftpCopyTmp";
        FTPClient ftpClient = null;
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.changeWorkingDirectory(remoteDirA);
            FTPFile[] allftpFiles = ftpClient.listFiles();
            List<String> validFtpFiles = new ArrayList<String>();
            for (FTPFile ftpf : allftpFiles) {
                if (ftpf.isFile() && fileNames.contains(ftpf.getName())) {
                    getFile(username, password, serverIp, port, remoteDirA, ftpf.getName(), tmpDir, encoding);// 远程文件拉去到本地临时目录
                    validFtpFiles.add(ftpf.getName());
                }
            }
            // 创建remoteDirB，无论存在与否。如果存在，则不会做动作；如果不存在，则创建
            // 如果要创建/home/pboss/abc 这个目录，则将parentDir设置成""就可以了
            makeDir(username, password, serverIp, port, "", remoteDirB, encoding);// 建立目录
            putFile(username, password, serverIp, port, tmpDir, validFtpFiles, remoteDirB, encoding);// 上传文件到远程目录
            FileUtil.cleanDir(new File(tmpDir));// 清空本地临时目录
            return validFtpFiles;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return null;
    }

    public static boolean deleteFiles(String username, String password, String serverIp, int port, String remotePath, List<String> fileNames, String encoding) {
        FTPClient ftpClient = null;
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.changeWorkingDirectory(remotePath);
            String[] fileNamesOnServer = ftpClient.listNames();
            Collections.sort(fileNames);
            if (Detect.notEmpty(fileNames) && Detect.notEmpty(fileNamesOnServer)) {
                for (int i = 0; i < fileNamesOnServer.length; i++) {
                    if (-1 < Collections.binarySearch(fileNames, fileNamesOnServer[i])) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("删除文件:" + fileNamesOnServer[i]);
                        }
                        ftpClient.dele(fileNamesOnServer[i]);
                        // int ret = ftpClient.dele(fileNamesOnServer[i]);
                        // return (250 == ret);// 250 DELE command successful
                    }
                }
            }
            return true;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return false;
    }

    public static boolean deleteFile(String username, String password, String serverIp, int port, String remotePath, String fileName, String encoding) {
        FTPClient ftpClient = null;
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.changeWorkingDirectory(remotePath);
            String[] fileNamesOnServer = ftpClient.listNames();

            if (Detect.notEmpty(fileName) && Detect.notEmpty(fileNamesOnServer)) {
                for (int i = 0; i < fileNamesOnServer.length; i++) {
                    if (fileName.equals(fileNamesOnServer[i])) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("删除文件:" + fileNamesOnServer[i]);
                        }
                        ftpClient.dele(fileNamesOnServer[i]);
                        // int ret = ftpClient.dele(fileNamesOnServer[i]);
                        // return (250 == ret);// 250 DELE command successful
                    }
                }
            }
            return true;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return false;
    }

    public static boolean deleteAllFiles(String username, String password, String serverIp, int port, String remotePath, String encoding) {
        List<String> fileNames = listFiles(username, password, serverIp, port, remotePath, encoding);
        return deleteFiles(username, password, serverIp, port, remotePath, fileNames, encoding);
    }

    public static boolean deleteAllFiles(String username, String password, String serverIp, int port, String remotePath) {
        return deleteAllFiles(username, password, serverIp, port, remotePath, DEFAULT_ENCODING);
    }

    public static boolean getFile(FtpConfig ftpConfig, List<String> fileNames, String localPath) {
        return getFile(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), ftpConfig.getDefaultRemoteDir(), fileNames, localPath, ftpConfig.getEncoding());
    }

    public static boolean getFile(String username, String password, String serverIp, int port, String remotePath, List<String> fileNames, String localPath) {
        return getFile(username, password, serverIp, port, remotePath, fileNames, localPath, DEFAULT_ENCODING);
    }

    public static boolean getFile(String username, String password, String serverIp, int port, String remotePath, String localPath, String encoding, boolean allFiles) {
        FTPClient ftpClient = null;
        FTPFile[] remoteFiles = null;
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.changeWorkingDirectory(remotePath);
            remoteFiles = ftpClient.listFiles();

            if (Detect.notEmpty(remoteFiles)) {
                for (FTPFile ftpFile : remoteFiles) {
                    File localFile = new File(localPath + File.separator + ftpFile.getName());
                    FileOutputStream fos = null;
                    try {
                        fos = new FileOutputStream(localFile);
                        ftpClient.retrieveFile(ftpFile.getName(), fos);
                    } catch (Exception e) {
                        logger.error("error", e);
                        return false;
                    } finally {
                        if (null != fos) {
                            try {
                                fos.close();
                            } catch (IOException e) {
                                logger.error("error", e);
                            }
                            fos = null;
                        }
                    }
                    /*
                     * 设置本地下载的文件的修改时间和ftp上的一致，保证时间一致性 但他只能保持日期一致，不能保持时间一致，下载的文件的时间都是0时0分0秒
                     */
                    localFile.setLastModified(ftpFile.getTimestamp().getTimeInMillis());
                }
            } else {
                logger.error("ftp的操作路径下没有任何文件！，FTP信息如下：用户名：" + username + ", 密码: " + password + ", IP地址: " + serverIp + ", 端口: " + port + ", 操作目录: " + remotePath);
                logger.info("");
                return false;
            }
            return true;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return false;
    }

    public static boolean getFile(String username, String password, String serverIp, int port, String remotePath, List<String> fileNames, String localPath, String encoding) {
        FTPClient ftpClient = null;
        FTPFile[] remoteFiles = null;

        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.changeWorkingDirectory(remotePath);
            remoteFiles = ftpClient.listFiles();
            Collections.sort(fileNames);

            if (Detect.notEmpty(remoteFiles)) {
                for (FTPFile ftpFile : remoteFiles) {
                    if (-1 < Collections.binarySearch(fileNames, ftpFile.getName())) {
                        File localFile = new File(localPath + File.separator + ftpFile.getName());
                        FileOutputStream fos = null;
                        try {
                            fos = new FileOutputStream(localFile);
                            ftpClient.retrieveFile(ftpFile.getName(), fos);
                        } catch (Exception e) {
                            logger.error("error", e);
                            return false;
                        } finally {
                            if (null != fos) {
                                try {
                                    fos.close();
                                } catch (IOException e) {
                                    logger.error("error", e);
                                }
                                fos = null;
                            }
                        }
                        /*
                         * 设置本地下载的文件的修改时间和ftp上的一致，保证时间一致性 但他只能保持日期一致，不能保持时间一致，下载的文件的时间都是0时0分0秒
                         */
                        localFile.setLastModified(ftpFile.getTimestamp().getTimeInMillis());
                    }
                }
            } else {
                logger.error("ftp的操作路径下没有任何文件！，FTP信息如下：用户名：" + username + ", 密码: " + password + ", IP地址: " + serverIp + ", 端口: " + port + ", 操作目录: " + remotePath);
                logger.info("");
                return false;
            }
            return true;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return false;
    }

    public static boolean getFile(String username, String password, String serverIp, int port, String remotePath, String fileName, String localPath, String encoding) {
        FTPClient ftpClient = null;
        FTPFile[] remoteFiles = null;

        remotePath = analysisFilePath(remotePath, fileName);
        fileName = analysisFileName(fileName);
        if (localPath != null) {
            File localDir = new File(localPath);
            if (!localDir.exists()) {
                localDir.mkdirs();
            }
        }
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.changeWorkingDirectory(remotePath);
            remoteFiles = ftpClient.listFiles();

            if (null != remoteFiles) {
                for (FTPFile ftpFile : remoteFiles) {
                    if (fileName.equals(ftpFile.getName())) {
                        File localFile = new File(localPath + File.separator + ftpFile.getName());
                        FileOutputStream fos = null;
                        try {
                            fos = new FileOutputStream(localFile);
                            ftpClient.retrieveFile(ftpFile.getName(), fos);
                        } catch (Exception e) {
                            logger.error("error", e);
                        } finally {
                            if (null != fos) {
                                try {
                                    fos.close();
                                } catch (IOException e) {
                                    logger.error("error", e);
                                }
                                fos = null;
                            }
                        }
                        /*
                         * 设置本地下载的文件的修改时间和ftp上的一致，保证时间一致性 但他只能保持日期一致，不能保持时间一致，下载的文件的时间都是0时0分0秒
                         */
                        localFile.setLastModified(ftpFile.getTimestamp().getTimeInMillis());
                    }
                }
            }
            return true;
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return false;
    }

    public static String getPath(String ftpUrl) {
        if (Detect.notEmpty(ftpUrl)) {
            try {
                URL url = new URL(ftpUrl);
                String path = url.getPath();
                path = path.substring(0, path.lastIndexOf("/") + 1);
                return path;
            } catch (MalformedURLException e) {
                return "";
            }
            /*
             * int idxOfAt = ftpUrl.indexOf("@"); int idxOfThirdColon = StringUtils.indexOf(ftpUrl, ":", idxOfAt); int idxOfPathRoot = StringUtils.indexOf(ftpUrl, "/", idxOfThirdColon); int
             * idxOfLastSlash = ftpUrl.lastIndexOf("/");
             *
             * if (0 >= idxOfPathRoot) { return ""; } if (0 >= idxOfLastSlash) { return ""; } return ftpUrl.substring(idxOfPathRoot, idxOfLastSlash+1);
             */
        }
        return "";
    }

    public static String getHostIp(String ftpUrl) {
        if (Detect.notEmpty(ftpUrl)) {
            try {
                URL url = new URL(ftpUrl);
                return url.getHost();
            } catch (MalformedURLException e) {
                return "";
            }
            /*
             * int idxOfAt = ftpUrl.indexOf("@"); int idxOfThirdColon = StringUtils.indexOf(ftpUrl, ":", idxOfAt);
             *
             * if (0 >= idxOfAt) { return ""; } if (0 >= idxOfThirdColon) { return ""; }
             *
             * return ftpUrl.substring(idxOfAt+1, idxOfThirdColon);
             */
        }
        return "";
    }

    public static int getHostPort(String ftpUrl) {
        if (Detect.notEmpty(ftpUrl)) {
            try {
                URL url = new URL(ftpUrl);
                return url.getPort();
            } catch (MalformedURLException e) {
                return 21;
            }
            /*
             * int idxOfAt = ftpUrl.indexOf("@"); int idxOfThirdColon = StringUtils.indexOf(ftpUrl, ":", idxOfAt); int idxOfThirdSlash = StringUtils.indexOf(ftpUrl, "/", idxOfThirdColon); if (0 >=
             * idxOfAt) { return 21; } if (0 >= idxOfThirdColon) { return 21; } if (0 >= idxOfThirdSlash) { return 21; } String port = ftpUrl.substring(idxOfThirdColon+1, idxOfThirdSlash); try {
             * return Integer.parseInt(port); } catch (Exception e) { return 21; }
             */
        }
        return 21;
    }

    public static String getFileName(String ftpUrl) {
        if (Detect.notEmpty(ftpUrl)) {
            try {
                URL url = new URL(ftpUrl);
                String path = url.getPath();
                path = path.substring(path.lastIndexOf("/") + 1);
                return path;
            } catch (MalformedURLException e) {
                return "";
            }
            /*
             * int idxOfLastSlash = ftpUrl.lastIndexOf("/"); if (0 >= idxOfLastSlash) { return ""; } return ftpUrl.substring(idxOfLastSlash+1);
             */
        }
        return "";
    }

    public static String getUsername(String ftpUrl) {
        if (Detect.notEmpty(ftpUrl)) {
            try {
                URL url = new URL(ftpUrl);
                String userInfo = url.getUserInfo();
                if (Detect.notEmpty(userInfo)) {
                    String[] info = userInfo.split(":");
                    return info[0];
                }
            } catch (MalformedURLException e) {
                return "";
            }
            /*
             * int idxOfFirstSlash = ftpUrl.lastIndexOf("//"); int idxOfAt = ftpUrl.indexOf("@"); if (0 >= idxOfFirstSlash) { return ""; } if (0 >= idxOfAt) { return ""; } String userAndPasswd =
             * ftpUrl.substring(idxOfFirstSlash+2, idxOfAt); String[] strs = userAndPasswd.split(":"); if (Detect.notEmpty(strs)) { return strs[0]; }
             */
        }
        return "";
    }

    public static String getPassword(String ftpUrl) {
        if (Detect.notEmpty(ftpUrl)) {
            try {
                URL url = new URL(ftpUrl);
                String userInfo = url.getUserInfo();
                if (Detect.notEmpty(userInfo)) {
                    String[] info = userInfo.split(":");
                    if (1 < info.length) {
                        return info[1];
                    }
                }
            } catch (MalformedURLException e) {
                return "";
            }
            /*
             * int idxOfFirstSlash = ftpUrl.lastIndexOf("//"); int idxOfAt = ftpUrl.indexOf("@"); if (0 >= idxOfFirstSlash) { return ""; } if (0 >= idxOfAt) { return ""; } String userAndPasswd =
             * ftpUrl.substring(idxOfFirstSlash+2, idxOfAt); String[] strs = userAndPasswd.split(":"); if (Detect.notEmpty(strs) && 2 == strs.length) { return strs[1]; }
             */
        }
        return "";
    }

    public static byte[] getFile(FtpConfig ftpConfig, String fileName) {
        return getFile(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), ftpConfig.getDefaultRemoteDir(), fileName, ftpConfig.getEncoding());
    }

    public static byte[] getFileUseLocation(FtpConfig ftpConfig, String location) {
        if (Detect.notEmpty(location)) {
            Map<String, String> map = getFileNameAndRemoteDir(ftpConfig, location);
            String fileName = map.containsKey("fileName") ? map.get("fileName") : StringUtils.EMPTY;
            String remoteDir = map.containsKey("remoteDir") ? map.get("remoteDir") : StringUtils.EMPTY;
            return getFile(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), remoteDir, fileName, ftpConfig.getEncoding());
        }
        return null;
    }

    public static byte[] getFile(String username, String password, String serverIp, int port, String remotePath, String fileName) {
        return getFile(username, password, serverIp, port, remotePath, fileName, DEFAULT_ENCODING);
    }

    public static byte[] getFile(String username, String password, String serverIp, int port, String remotePath, String fileName, String encoding) {
        FTPClient ftpClient = null;
        // FTPFile[] remoteFiles = null;
        byte[] bytes = null;

        remotePath = analysisFilePath(remotePath, fileName);
        fileName = analysisFileName(fileName);

        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.changeWorkingDirectory(remotePath);
            // remoteFiles = ftpClient.listFiles();

            if (Detect.notEmpty(fileName)) {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                try {
                    ftpClient.retrieveFile(fileName, bos);
                    bytes = bos.toByteArray();
                    return bytes;
                } catch (Exception e) {
                    logger.error("error", e);
                } finally {
                    if (null != bos) {
                        try {
                            bos.close();
                        } catch (IOException e) {
                            logger.error("error", e);
                        }
                        bos = null;
                    }
                }
            }
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return new byte[0];
    }

    public static FTPFile[] getFiles(FtpConfig ftpConfig) throws Exception {
        FTPClient ftpClient = connect(ftpConfig);
        ftpClient.changeWorkingDirectory(ftpConfig.getDefaultRemoteDir());
        return ftpClient.listFiles();
    }

    /**
     * 分析ftp的文件目录路径 传参时有可能用户不设置默认根路径，而把路径完整信息放在文件名上，所以需要额外分析，设置文件的目录路径
     *
     * @param remotePath
     * @param fileName
     * @return
     */
    static String analysisFilePath(String remotePath, String fileName) {
        if (Detect.notEmpty(remotePath)) {
            return remotePath;
        } else if (!Detect.notEmpty(fileName)) {
            throw new IllegalArgumentException("下载的文件名不能为空");
        } else {
            String path;
            int idx = fileName.lastIndexOf("/");
            if (0 > idx) {
                idx = fileName.lastIndexOf("\\");
                if (0 > idx) {
                    // idx = 0;
                    // 路径为空，文件名不是以\或/开头则默认是根路径
                    return "/";
                }
            }
            path = fileName.substring(0, idx + 1);
            return path;
        }
    }

    /**
     * 分析ftp的文件名称 传参时有可能用户不设置默认根路径，而把路径完整信息放在文件名上，所以需要额外分析，设置文件名称
     *
     * @param remotePath
     * @param fileName
     * @return
     */
    static String analysisFileName(String fileName) {
        if (!Detect.notEmpty(fileName)) {
            throw new IllegalArgumentException("下载的文件名不能为空");
        } else {
            int idx = fileName.lastIndexOf("/");
            if (0 > idx) {
                idx = fileName.lastIndexOf("\\");
                if (0 > idx) {
                    // idx = 0;
                    // 文件名不是以\或/开头则原样返回
                    return fileName;
                }
            }
            fileName = fileName.substring(idx + 1);
            return fileName;
        }
    }

    public static List<String> listFiles(FtpConfig ftpConfig) {
        return listFiles(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), ftpConfig.getDefaultRemoteDir(), ftpConfig.getEncoding());
    }

    public static List<String> listFiles(String username, String password, String serverIp, int port, String remotePath) {
        return listFiles(username, password, serverIp, port, remotePath, DEFAULT_ENCODING);
    }

    public static List<String> listFiles(String username, String password, String serverIp, int port, String remotePath, String encoding) {
        int fileCacheSize = 5;
        FTPClient ftpClient = null;
        List<String> fileNames = new ArrayList<String>();
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            FTPListParseEngine f = ftpClient.initiateListParsing(remotePath);
            while (null != f && f.hasNext()) {
                FTPFile[] files = f.getNext(fileCacheSize);
                for (FTPFile file : files) {
                    fileNames.add(file.getName());
                }
            }
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return fileNames;
    }

    /**
     * 只显示指定路径下的文件列表（不包含文件夹）
     *
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param remotePath
     * @param encoding
     * @return
     */
    public static List<String> listOnlyFiles(String username, String password, String serverIp, int port, String remotePath, String encoding) {
        int fileCacheSize = 5;
        FTPClient ftpClient = null;
        List<String> fileNames = new ArrayList<String>();
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            FTPListParseEngine f = ftpClient.initiateListParsing(remotePath);
            while (null != f && f.hasNext()) {
                FTPFile[] files = f.getNext(fileCacheSize);
                for (FTPFile file : files) {
                    if (file.isFile()) {
                        fileNames.add(file.getName());
                    }
                }
            }
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return fileNames;
    }

    public static FTPFile[] listFilesByPath(String username, String password, String serverIp, int port, String remotePath, String encoding) {
        FTPClient ftpClient = null;
        FTPFile[] files = null;
        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            files = ftpClient.listFiles(remotePath);
        } catch (Throwable e) {
            logger.error("error", e);
        } finally {
            disconnect(ftpClient);
        }
        return files;
    }

    public static boolean putFile(FtpConfig ftpConfig, String localPath, List<String> fileNames) {
        return putFile(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), localPath, fileNames, ftpConfig.getDefaultRemoteDir(), ftpConfig.getEncoding());
    }

    public static boolean putFile(String username, String password, String serverIp, int port, String localPath, List<String> fileNames, String remotePath) {
        return putFile(username, password, serverIp, port, localPath, fileNames, remotePath, DEFAULT_ENCODING);
    }

    public static boolean putFile(String username, String password, String serverIp, int port, String localPath, List<String> fileNames, String remotePath, String encoding) {
        FTPClient ftpClient = null;
        FileInputStream in = null;

        if (Detect.notEmpty(fileNames)) {
            try {
                ftpClient = connect(username, password, serverIp, port, encoding);
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                ftpClient.changeWorkingDirectory(remotePath);
                for (String fileName : fileNames) {
                    try {
                        in = new FileInputStream(new File(localPath + File.separator + fileName));
                        if (logger.isDebugEnabled()) {
                            logger.debug("上传文件开始: " + localPath + File.separator + fileName);
                        }
                        ftpClient.storeFile(fileName, in);
                        if (logger.isDebugEnabled()) {
                            logger.debug("上传文件完毕: " + localPath + File.separator + fileName);
                        }
                    } catch (Throwable e) {
                        logger.error("error", e);
                        return false;
                    } finally {
                        if (null != in) {
                            try {
                                in.close();
                            } catch (IOException e) {
                                logger.error("error", e);
                                in = null;
                            }
                        }
                    }
                }
                return true;
            } catch (Exception e) {
                logger.error("error", e);
                return false;
            } finally {
                disconnect(ftpClient);
            }
        }
        return false;
    }

    /**
     * 上传时默认采用gbk编码，适用windows平台的ftp server
     *
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param fileName
     * @param inputStream
     * @param remotePath
     * @return
     */
    public static boolean putFile(String username, String password, String serverIp, int port, String fileName, InputStream inputStream, String remotePath) {
        return putFile(username, password, serverIp, port, fileName, inputStream, remotePath, DEFAULT_ENCODING);
    }

    public static boolean putFile(FtpConfig ftpConfig, String fileName, InputStream inputStream) {
        return putFile(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), fileName, inputStream, ftpConfig.getDefaultRemoteDir(), ftpConfig.getEncoding());
    }

    private static Map<String, String> getFileNameAndRemoteDir(FtpConfig ftpConfig, String location) {
        Map<String, String> result = new HashMap<String, String>();
        if (Detect.notEmpty(location)) {
            String[] locations = StringUtils.removeStart(location, SEPARATOR).split(SEPARATOR);
            String fileName = locations[locations.length - 1];
            String remoteDir = StringUtils.isBlank(ftpConfig.getDefaultRemoteDir()) ? SEPARATOR : ftpConfig.getDefaultRemoteDir();
            if (locations.length > 1) {
                remoteDir = (Detect.notEmpty(remoteDir)) ? StringUtils.removeEnd(remoteDir, SEPARATOR) : StringUtils.EMPTY;
                for (int i = 0; i < locations.length - 1; i++) {
                    remoteDir += SEPARATOR + locations[i];
                }
            }
            result.put("fileName", fileName);
            result.put("remoteDir", remoteDir);
        }
        return result;
    }

    public static boolean putFileUseLocation(FtpConfig ftpConfig, String location, InputStream inputStream) {
        if (Detect.notEmpty(location)) {
            Map<String, String> map = getFileNameAndRemoteDir(ftpConfig, location);
            String fileName = map.containsKey("fileName") ? map.get("fileName") : StringUtils.EMPTY;
            String remoteDir = map.containsKey("remoteDir") ? map.get("remoteDir") : StringUtils.EMPTY;
            return putFile(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), fileName, inputStream, remoteDir, ftpConfig.getEncoding());
        }
        return false;
    }

    /**
     * 上传文件
     *
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param fileName
     * @param inputStream
     * @param remotePath
     * @param encoding
     * @return
     */
    public static boolean putFile(String username, String password, String serverIp, int port, String fileName, InputStream inputStream, String remotePath, String encoding) {
        FTPClient ftpClient = null;

        if (Detect.notEmpty(fileName)) {
            try {
                ftpClient = connect(username, password, serverIp, port, encoding);
                ftpClient.changeWorkingDirectory(remotePath);
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                try {
                    if (logger.isDebugEnabled()) {
                        logger.debug("上传文件开始: " + fileName);
                    }
                    boolean success = ftpClient.storeFile(fileName, inputStream);
                    if (success) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("上传文件完毕: " + fileName);
                        }
                    } else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("上传文件失败: " + fileName);
                        }
                    }
                    return success;
                } catch (Throwable e) {
                    logger.error("error", e);
                    return false;
                }
            } catch (Throwable e) {
                logger.error("error", e);
                return false;
            } finally {
                disconnect(ftpClient);
            }
        }
        return false;
    }


    public static boolean makeDir(String username, String password, String serverIp, int port, String remotePath, String subDirName) {
        return makeDir(username, password, serverIp, port, remotePath, subDirName, DEFAULT_ENCODING);
    }

    public static boolean makeDir(String username, String password, String serverIp, int port, String remotePath, String subDirName, String encoding) {
        FTPClient ftpClient = null;

        if (Detect.notEmpty(subDirName)) {
            try {
                ftpClient = connect(username, password, serverIp, port, encoding);
                ftpClient.changeWorkingDirectory(remotePath);
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                try {
                    boolean success = ftpClient.makeDirectory(subDirName);
                    return success;
                } catch (Throwable e) {
                    logger.error("error", e);
                    return false;
                }
            } catch (Throwable e) {
                logger.error("error", e);
                return false;
            } finally {
                disconnect(ftpClient);
            }
        }
        return false;
    }

    /**
     * 递归创建目录
     *
     * @param ftpClient
     * @param remote
     * @return
     * @throws IOException
     */
    public static boolean crateDirecroty(FTPClient ftpClient, String remote) throws IOException {
        boolean success = true;
        String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
        if (!directory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(new String(directory))) {
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            while (true) {
                String subDirectory = new String(remote.substring(start, end));
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        ftpClient.changeWorkingDirectory(subDirectory);
                    } else {
                        logger.error("创建目录失败");
                        success = false;
                        return success;
                    }
                }
                start = end + 1;
                end = directory.indexOf("/", start);
                if (end <= start) {
                    break;
                }
            }
        }
        return success;
    }

    private static FTPClient connect(FtpConfig ftpConfig) throws Exception {
        return connect(ftpConfig.getUsername(), ftpConfig.getPassword(), ftpConfig.getIp(), ftpConfig.getPort(), ftpConfig.getEncoding());
    }

    private static FTPClient connect(String username, String password, String serverIp, int port, String encoding) throws Exception {
        FTPClient ftpClient = null;
        try {
            ftpClient = new FTPClient();
            ftpClient.setControlEncoding(encoding);
            ftpClient.connect(serverIp, port);
            ftpClient.login(username, password);
            ftpClient.enterLocalPassiveMode();
            int returnCode = ftpClient.pasv();
            returnCode = ftpClient.getReplyCode();
            ftpClient.setDataTimeout(10000);
            if (!FTPReply.isPositiveCompletion(returnCode)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("FTP server refused connection.returnCode=" + returnCode);
                }
                throw new Exception("FTP server refused connection.returnCode=" + returnCode);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("connected to FTP server. ip=" + serverIp + ", port=" + port);
            }
            return ftpClient;
        } catch (Throwable e) {
            logger.error("username=" + username + ", password=" + password + ", serverIp=" + serverIp + ", port=" + port + ", encoding=" + encoding, e);
            if (null != ftpClient) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e1) {
                }
                ftpClient = null;
            }
            throw new Exception(e);
        }
    }

    /**
     * 优化下： ftp.isConnected最好要写在finally里面，不要直接写在ftp.logout()后面, 这样子写会有很大的隐患。
     *
     * @param ftpClient
     * @author TaoPingPing
     */
    private static void disconnect(FTPClient ftpClient) {
        if (null != ftpClient) {
            try {
                ftpClient.logout();
            } catch (IOException e) {
                logger.error("error", e);
            } finally {
                if (ftpClient.isConnected()) {
                    try {
                        ftpClient.disconnect();
                    } catch (IOException ioe) {
                    }
                }
                ftpClient = null;
            }
        }
    }

    public static void main(String s[]) {
        String ip = "192.168.120.152";
        int port = 21;
        String remotePath = "/bpm/files";
        // String enCoding = "utf-8";
        String userName = "wusuirong";
        String userPassword = "aaaaaa";
        try {
            backupFtpFile("21sf,..。。我当时absds".getBytes(), ip, String.valueOf(port), userName, userPassword, remotePath, "avc.txt");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("error", e);
        }

    }

    /**
     * 从Bossftp上将每日文件备份到综资ftp
     *
     * @param bytes
     * @param userName
     * @param userPassword
     * @param path
     * @param fileName
     * @return
     * @throws IOException
     */
    public static boolean backupFtpFile(byte[] bytes, String ip, String port, String userName, String userPassword, String path, String fileName) throws IOException {
        FTPClient ftpClient = null;
        ByteArrayInputStream is = null;
        boolean b = false;
        try {
            is = new ByteArrayInputStream(bytes);
            ftpClient = new FTPClient();
            ftpClient.connect(ip, Integer.valueOf(port));
            ftpClient.login(userName, userPassword);
            ftpClient.changeWorkingDirectory(path);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            b = ftpClient.storeFile(new String(fileName.getBytes("GBK"), "iso-8859-1"), is);
            if (b) {
                logger.info("上传成功，文件大小为：" + bytes.length + "bytes" + "\n\r" + "文件保存url:ftp://" + ip + ":" + port + path);
            } else {
                logger.info("文件上传到备份FTP失败，文件名为：" + fileName);
            }
        } catch (Exception e) {
            logger.error("文件上传到备份FTP失败，文件名为：" + fileName, e);
            return false;
        } finally {
            IOUtils.closeQuietly(is);
            disconnect(ftpClient);
        }
        return b;
    }

    /**
     * 重命名远程FTP指定文件
     *
     * @param oldFileName
     * @param newFileName
     * @param username
     * @param password
     * @param serverIp
     * @param port
     * @param remotePath
     * @param encoding
     * @return
     */
    public static boolean renameFile(String oldFileName, String newFileName, String username, String password, String serverIp, int port, String remotePath, String encoding) {
        FTPClient ftpClient = null;

        try {
            ftpClient = connect(username, password, serverIp, port, encoding);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.changeWorkingDirectory(remotePath);
            boolean status = ftpClient.rename(oldFileName, newFileName);
            return status;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            disconnect(ftpClient);
        }
    }
}
